package web.servlet;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.RandomStringUtils;

import web.servlet.dto.DtoFactory;
import data.model.User;

public class RegisterServlet extends AbstractJsonCapableServlet {

    private static final int FIVE_MINUTES_IN_MILLISECONDS = 5 * 60 * 1000;

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        if (!dataLayer.isEmailExist(request.getParameter("email"))) {
            jsonHandler.writeAsJson(DtoFactory.createValidateEmailSuccess(), response);
        } else {
            jsonHandler.writeAsJson(DtoFactory.createErrorMessage("Email address already exists"), response);
        }
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        final String email = request.getParameter("email");

        final User user = dataLayer.findUserByEmail(email);

        if (user == null) {
            final String token = generateConfirmToken();
            createNewUser(request.getParameter("email"), token);
            sendConfirmEmail(request.getParameter("email"), token);
            jsonHandler.writeAsJson(DtoFactory.createMessage("An email has been sent to your email address to confirm your registration"), response);
        } else if (user.getConfirmationToken() != null) {
            if (new Date().getTime() - user.getLastRegistration().getTime() >= FIVE_MINUTES_IN_MILLISECONDS) {
                updateLastRegistrationDate(user);
                sendConfirmEmail(request.getParameter("email"), user.getConfirmationToken());

                jsonHandler.writeAsJson(DtoFactory.createMessage("An email has been sent to your email address to confirm your registration"), response);
            } else {
                jsonHandler.writeAsJson(DtoFactory
                        .createErrorMessage("A confirmation email has been sent recently. Please wait at least 5 minutes before retry"), response);
            }
        } else {
            jsonHandler.writeAsJson(DtoFactory.createErrorMessage("User already exists"), response);
        }
    }

    private void updateLastRegistrationDate(final User user) {
        user.setLastRegistration(new Date());
        dataLayer.updateObject(user);
    }

    private String generateConfirmToken() {
        return RandomStringUtils.randomAlphanumeric(32);
    }

    private User createNewUser(String email, String token) {
        final User newUser = new User();
        newUser.setEmail(email);
        newUser.setConfirmationToken(token);
        newUser.setLastRegistration(new Date());
        dataLayer.addObject(newUser);

        return newUser;
    }

    private void sendConfirmEmail(String email, String token) {
        final Map<String, String> mailTemplateParams = new HashMap<String, String>();
        mailTemplateParams.put("confirmation.url", constructConfirmUrl(email, token));

        emailLayer.sendEmail(email, "confirmation.subject", "confirmation.body", mailTemplateParams);
    }

    private String constructConfirmUrl(String emailAddress, String token) {
        try {
            final StringBuilder url = new StringBuilder();
            url.append("email=" + URLEncoder.encode(emailAddress, "UTF-8"));
            url.append("&token=" + URLEncoder.encode(token, "UTF-8"));
            url.append("&command=" + URLEncoder.encode("confirmRegister", "UTF-8"));

            return HOST + "/index.jsp?" + url.toString();
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }
}
